home *** CD-ROM | disk | FTP | other *** search
- #include "port.h"
- #include "sparse_int.h"
-
- /*
- * free-lists are only used if 'FAST_AND_LOOSE' is set; this is because
- * we lose the debugging capability of libmm_t which trashes objects when
- * they are free'd. However, FAST_AND_LOOSE is much faster if matrices
- * are created and freed frequently.
- */
-
- #ifdef FAST_AND_LOOSE
- sm_element *sm_element_freelist;
- sm_row *sm_row_freelist;
- sm_col *sm_col_freelist;
- #endif
-
-
- sm_matrix *sm_alloc(void)
- {
- register sm_matrix *A;
-
- A = ALLOC(sm_matrix, 1);
- A->rows = NIL(sm_row *);
- A->cols = NIL(sm_col *);
- A->nrows = A->ncols = 0;
- A->rows_size = A->cols_size = 0;
- A->first_row = A->last_row = NIL(sm_row);
- A->first_col = A->last_col = NIL(sm_col);
- A->user_word = NIL(char); /* for our user ... */
- return A;
- }
-
-
- sm_matrix *sm_alloc_size(int row, int col)
- {
- register sm_matrix *A;
-
- A = sm_alloc();
- sm_resize(A, row, col);
- return A;
- }
-
-
- void sm_free(sm_matrix *A)
- {
- #ifdef FAST_AND_LOOSE
- register sm_row *prow;
-
- if (A->first_row != 0) {
- for(prow = A->first_row; prow != 0; prow = prow->next_row) {
- /* add the elements to the free list of elements */
- prow->last_col->next_col = sm_element_freelist;
- sm_element_freelist = prow->first_col;
- }
-
- /* Add the linked list of rows to the row-free-list */
- A->last_row->next_row = sm_row_freelist;
- sm_row_freelist = A->first_row;
-
- /* Add the linked list of cols to the col-free-list */
- A->last_col->next_col = sm_col_freelist;
- sm_col_freelist = A->first_col;
- }
- #else
- register sm_row *prow, *pnext_row;
- register sm_col *pcol, *pnext_col;
-
- for(prow = A->first_row; prow != 0; prow = pnext_row) {
- pnext_row = prow->next_row;
- sm_row_free(prow);
- }
- for(pcol = A->first_col; pcol != 0; pcol = pnext_col) {
- pnext_col = pcol->next_col;
- pcol->first_row = pcol->last_row = NIL(sm_element);
- sm_col_free(pcol);
- }
- #endif
-
- /* Free the arrays to map row/col numbers into pointers */
- FREE(A->rows);
- FREE(A->cols);
- FREE(A);
- }
-
-
- sm_matrix *sm_dup(sm_matrix *A)
- {
- register sm_row *prow;
- register sm_element *p;
- register sm_matrix *B;
-
- B = sm_alloc();
- if (A->last_row != 0) {
- sm_resize(B, A->last_row->row_num, A->last_col->col_num);
- for(prow = A->first_row; prow != 0; prow = prow->next_row) {
- for(p = prow->first_col; p != 0; p = p->next_col) {
- (void) sm_insert(B, p->row_num, p->col_num);
- }
- }
- }
- return B;
- }
-
-
- void sm_resize(register sm_matrix *A, int row, int col)
- {
- register int i, new_size;
-
- if (row >= A->rows_size) {
- new_size = MAX(A->rows_size*2, row+1);
- A->rows = REALLOC(sm_row *, A->rows, new_size);
- for(i = A->rows_size; i < new_size; i++) {
- A->rows[i] = NIL(sm_row);
- }
- A->rows_size = new_size;
- }
-
- if (col >= A->cols_size) {
- new_size = MAX(A->cols_size*2, col+1);
- A->cols = REALLOC(sm_col *, A->cols, new_size);
- for(i = A->cols_size; i < new_size; i++) {
- A->cols[i] = NIL(sm_col);
- }
- A->cols_size = new_size;
- }
- }
-
-
- /*
- * insert -- insert a value into the matrix
- */
- sm_element *sm_insert(register sm_matrix *A, register int row, register int col)
- {
- register sm_row *prow;
- register sm_col *pcol;
- register sm_element *element;
- sm_element *save_element;
-
- if (row >= A->rows_size || col >= A->cols_size) {
- sm_resize(A, row, col);
- }
-
- prow = A->rows[row];
- if (prow == NIL(sm_row)) {
- prow = A->rows[row] = sm_row_alloc();
- prow->row_num = row;
- sorted_insert(sm_row, A->first_row, A->last_row, A->nrows,
- next_row, prev_row, row_num, row, prow);
- }
-
- pcol = A->cols[col];
- if (pcol == NIL(sm_col)) {
- pcol = A->cols[col] = sm_col_alloc();
- pcol->col_num = col;
- sorted_insert(sm_col, A->first_col, A->last_col, A->ncols,
- next_col, prev_col, col_num, col, pcol);
- }
-
- /* get a new item, save its address */
- sm_element_alloc(element);
- save_element = element;
-
- /* insert it into the row list */
- sorted_insert(sm_element, prow->first_col, prow->last_col,
- prow->length, next_col, prev_col, col_num, col, element);
-
- /* if it was used, also insert it into the column list */
- if (element == save_element) {
- sorted_insert(sm_element, pcol->first_row, pcol->last_row,
- pcol->length, next_row, prev_row, row_num, row, element);
- } else {
- /* otherwise, it was already in matrix -- free element we allocated */
- sm_element_free(save_element);
- }
- return element;
- }
-
-
- sm_element *sm_find(sm_matrix *A, int rownum, int colnum)
- {
- sm_row *prow;
- sm_col *pcol;
-
- prow = sm_get_row(A, rownum);
- if (prow == NIL(sm_row)) {
- return NIL(sm_element);
- } else {
- pcol = sm_get_col(A, colnum);
- if (pcol == NIL(sm_col)) {
- return NIL(sm_element);
- }
- if (prow->length < pcol->length) {
- return sm_row_find(prow, colnum);
- } else {
- return sm_col_find(pcol, rownum);
- }
- }
- }
-
-
- void sm_remove(sm_matrix *A, int rownum, int colnum)
- {
- sm_remove_element(A, sm_find(A, rownum, colnum));
- }
-
-
-
- void sm_remove_element(register sm_matrix *A, register sm_element *p)
- {
- register sm_row *prow;
- register sm_col *pcol;
-
- if (p == 0) return;
-
- /* Unlink the element from its row */
- prow = sm_get_row(A, p->row_num);
- dll_unlink(p, prow->first_col, prow->last_col,
- next_col, prev_col, prow->length);
-
- /* if no more elements in the row, discard the row header */
- if (prow->first_col == NIL(sm_element)) {
- sm_delrow(A, p->row_num);
- }
-
- /* Unlink the element from its column */
- pcol = sm_get_col(A, p->col_num);
- dll_unlink(p, pcol->first_row, pcol->last_row,
- next_row, prev_row, pcol->length);
-
- /* if no more elements in the column, discard the column header */
- if (pcol->first_row == NIL(sm_element)) {
- sm_delcol(A, p->col_num);
- }
-
- sm_element_free(p);
- }
-
- void sm_delrow(sm_matrix *A, int i)
- {
- register sm_element *p, *pnext;
- sm_col *pcol;
- sm_row *prow;
-
- prow = sm_get_row(A, i);
- if (prow != NIL(sm_row)) {
- /* walk across the row */
- for(p = prow->first_col; p != 0; p = pnext) {
- pnext = p->next_col;
-
- /* unlink the item from the column (and delete it) */
- pcol = sm_get_col(A, p->col_num);
- sm_col_remove_element(pcol, p);
-
- /* discard the column if it is now empty */
- if (pcol->first_row == NIL(sm_element)) {
- sm_delcol(A, pcol->col_num);
- }
- }
-
- /* discard the row -- we already threw away the elements */
- A->rows[i] = NIL(sm_row);
- dll_unlink(prow, A->first_row, A->last_row,
- next_row, prev_row, A->nrows);
- prow->first_col = prow->last_col = NIL(sm_element);
- sm_row_free(prow);
- }
- }
-
- void sm_delcol(sm_matrix *A, int i)
- {
- register sm_element *p, *pnext;
- sm_row *prow;
- sm_col *pcol;
-
- pcol = sm_get_col(A, i);
- if (pcol != NIL(sm_col)) {
- /* walk down the column */
- for(p = pcol->first_row; p != 0; p = pnext) {
- pnext = p->next_row;
-
- /* unlink the element from the row (and delete it) */
- prow = sm_get_row(A, p->row_num);
- sm_row_remove_element(prow, p);
-
- /* discard the row if it is now empty */
- if (prow->first_col == NIL(sm_element)) {
- sm_delrow(A, prow->row_num);
- }
- }
-
- /* discard the column -- we already threw away the elements */
- A->cols[i] = NIL(sm_col);
- dll_unlink(pcol, A->first_col, A->last_col,
- next_col, prev_col, A->ncols);
- pcol->first_row = pcol->last_row = NIL(sm_element);
- sm_col_free(pcol);
- }
- }
-
- void sm_copy_row(register sm_matrix *dest, int dest_row, sm_row *prow)
- {
- register sm_element *p;
-
- for(p = prow->first_col; p != 0; p = p->next_col) {
- (void) sm_insert(dest, dest_row, p->col_num);
- }
- }
-
-
- void sm_copy_col(register sm_matrix *dest, int dest_col, sm_col *pcol)
- {
- register sm_element *p;
-
- for(p = pcol->first_row; p != 0; p = p->next_row) {
- (void) sm_insert(dest, dest_col, p->row_num);
- }
- }
-
-
- sm_row *sm_longest_row(sm_matrix *A)
- {
- register sm_row *large_row, *prow;
- register int max_length;
-
- max_length = 0;
- large_row = NIL(sm_row);
- for(prow = A->first_row; prow != 0; prow = prow->next_row) {
- if (prow->length > max_length) {
- max_length = prow->length;
- large_row = prow;
- }
- }
- return large_row;
- }
-
-
- sm_col *sm_longest_col(sm_matrix *A)
- {
- register sm_col *large_col, *pcol;
- register int max_length;
-
- max_length = 0;
- large_col = NIL(sm_col);
- for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) {
- if (pcol->length > max_length) {
- max_length = pcol->length;
- large_col = pcol;
- }
- }
- return large_col;
- }
-
-
- int sm_num_elements(sm_matrix *A)
- {
- register sm_row *prow;
- register int num;
-
- num = 0;
- sm_foreach_row(A, prow) {
- num += prow->length;
- }
- return num;
- }
-
- int sm_read(FILE *fp, sm_matrix **A)
- {
- int i, j, err;
-
- *A = sm_alloc();
- while (! feof(fp)) {
- err = fscanf(fp, "%d %d", &i, &j);
- if (err == EOF) {
- return 1;
- } else if (err != 2) {
- return 0;
- }
- (void) sm_insert(*A, i, j);
- }
- return 1;
- }
-
-
- int
- sm_read_compressed(FILE *fp, sm_matrix **A)
- {
- int i, j, k, nrows, ncols;
- unsigned long x;
-
- *A = sm_alloc();
- if (fscanf(fp, "%d %d", &nrows, &ncols) != 2) {
- return 0;
- }
- sm_resize(*A, nrows, ncols);
-
- for(i = 0; i < nrows; i++) {
- if (fscanf(fp, "%lx", &x) != 1) {
- return 0;
- }
- for(j = 0; j < ncols; j += 32) {
- if (fscanf(fp, "%lx", &x) != 1) {
- return 0;
- }
- for(k = j; x != 0; x >>= 1, k++) {
- if (x & 1) {
- (void) sm_insert(*A, i, k);
- }
- }
- }
- }
- return 1;
- }
-
-
- void sm_write(FILE *fp, sm_matrix *A)
- {
- register sm_row *prow;
- register sm_element *p;
-
- for(prow = A->first_row; prow != 0; prow = prow->next_row) {
- for(p = prow->first_col; p != 0; p = p->next_col) {
- (void) fprintf(fp, "%d %d\n", p->row_num, p->col_num);
- }
- }
- }
-
- void sm_print(FILE *fp, sm_matrix *A)
- {
- register sm_row *prow;
- register sm_col *pcol;
- int c;
-
- if (A->last_col->col_num >= 100) {
- (void) fprintf(fp, " ");
- for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) {
- (void) fprintf(fp, "%d", (pcol->col_num / 100)%10);
- }
- putc('\n', fp);
- }
-
- if (A->last_col->col_num >= 10) {
- (void) fprintf(fp, " ");
- for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) {
- (void) fprintf(fp, "%d", (pcol->col_num / 10)%10);
- }
- putc('\n', fp);
- }
-
- (void) fprintf(fp, " ");
- for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) {
- (void) fprintf(fp, "%d", pcol->col_num % 10);
- }
- putc('\n', fp);
-
- (void) fprintf(fp, " ");
- for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) {
- (void) fprintf(fp, "-");
- }
- putc('\n', fp);
-
- for(prow = A->first_row; prow != 0; prow = prow->next_row) {
- (void) fprintf(fp, "%3d:", prow->row_num);
-
- for(pcol = A->first_col; pcol != 0; pcol = pcol->next_col) {
- c = sm_row_find(prow, pcol->col_num) ? '1' : '.';
- putc(c, fp);
- }
- putc('\n', fp);
- }
- }
-
-
- void sm_dump(sm_matrix *A, char *s, int max)
- {
- FILE *fp = stdout;
-
- (void) fprintf(fp, "%s %d rows by %d cols\n", s, A->nrows, A->ncols);
- if (A->nrows < max) {
- sm_print(fp, A);
- }
- }
-
- void
- sm_cleanup()
- {
- #ifdef FAST_AND_LOOSE
- register sm_element *p, *pnext;
- register sm_row *prow, *pnextrow;
- register sm_col *pcol, *pnextcol;
-
- for(p = sm_element_freelist; p != 0; p = pnext) {
- pnext = p->next_col;
- FREE(p);
- }
- sm_element_freelist = 0;
-
- for(prow = sm_row_freelist; prow != 0; prow = pnextrow) {
- pnextrow = prow->next_row;
- FREE(prow);
- }
- sm_row_freelist = 0;
-
- for(pcol = sm_col_freelist; pcol != 0; pcol = pnextcol) {
- pnextcol = pcol->next_col;
- FREE(pcol);
- }
- sm_col_freelist = 0;
- #endif
- }
-